using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using UnityGameFramework.Runtime;
using LS.Digitize;
using LS.Saving;
using LS.UnityExtensions;

namespace LS.Saving
{
    public class DefaultSavingHelper : SaveHelperBase
    {
        // private readonly SavingSerializer m_Serializer = new SavingSerializer();
        // private const string Split = ":";
        private ISerializer<DataObject> m_Serializer = null;
        protected virtual void Awake()
        {
            // m_Serializer.RegisterSerializeCallback(0, SerializeDefaultSavingCallBase);
            // m_Serializer.RegisterDeserializeCallback(0, DeserializeDefaultSavingCallBase);
            m_Serializer = SerializerUtil.GetOrCreateSerializer(typeof(DataObject)) as ISerializer<DataObject>;
        }

        public override void GetAllFiles(string folder, string searchExt, Action<IDataFile[]> onResult)
        {
            
        }

        public override void LoadFile(IDataFile file, Database dataBase, Action<bool, string> onResult)
        {
            string path = file.FullPath;
            if (!file.Existed)
            {
                onResult?.Invoke(false, $"File with path {path} not existed.");
                return;
            }

            try
            {
                using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
                {
                    ISerializer<DataObject> serializer = SerializerUtil.GetOrCreateSerializer(typeof(DataObject)) as ISerializer<DataObject>;
                    Dictionary<string, object> dict = new Dictionary<string, object>();
                    using (Reader reader = new JsonReader(fileStream))
                    {
                        string propertyName = null;
                        object value = null;
                        while (true)
                        {
                            propertyName = reader.ReadPropertyName();
                            if(propertyName == null) break;
                            value = serializer.ReadData(reader).value;
                            dict.Add(propertyName, value);
                        }
                    }
                    DataBaseExtension.Inject(dataBase, dict);
                }
                dataBase.ClearDirty();
                onResult?.Invoke(true, "Successfully loaded file.");
            }
            catch (Exception e)
            {
                Log.Error("Read file failure with exception '{0}'.", e);
                onResult?.Invoke(false, $"Read file failure with exception '{e.Message}'.");
            }
        }

        public override void SaveFile(IDataFile file, Database dataBase, Action<bool, string> onResult)
        {
            string path = file.FullPath;
            if (!file.Existed)
            {
                onResult?.Invoke(false, $"File with path {path} not existed.");
                return;
            }
            
            try
            {
                ISerializer<DataObject> serializer = SerializerUtil.GetOrCreateSerializer(typeof(DataObject)) as ISerializer<DataObject>;
                using (FileStream fileStream = new FileStream(path, FileMode.Create, FileAccess.Write))
                {
                    using (Writer writer = new JsonWriter(fileStream))
                    {
                        foreach (KeyValuePair<string, object> keyValuePair in dataBase.GetDataDictionary())
                        {
                            using (writer.WritePropertyScope(keyValuePair.Key))
                            {
                                DataObject obj = new DataObject()
                                {
                                    type = keyValuePair.Value.GetType(),
                                    value = keyValuePair.Value
                                };
                                serializer.WriteData(writer, obj);
                            }
                        }
                    }
                }
                dataBase.ClearDirty();
                onResult?.Invoke(true, "Successfully saved file.");
            }
            catch (Exception exception)
            {
                Log.Error("Read file failure with exception '{0}'.", exception);
                onResult?.Invoke(false, $"Read file failure with exception '{exception.Message}'.");
            }
        }

        public override void DeleteFile(IDataFile file)
        {
            SavingIO.DeleteFile(file.FullPath);
        }

        public override IDataFile CreateDataFile(string folder, string fileName, string fileExtension)
        {
            return new DefaultDataFile(folder, fileName, fileExtension);
        }

        public override IDataFile CreateDataFile(string filePath)
        {
            return new DefaultDataFile(filePath);
        }

        protected virtual bool SerializeDefaultSavingCallBase(Stream stream, Dictionary<string, object> data)
        {
            try
            {
                // using (BinaryWriter binaryWriter = new BinaryWriter(stream, Encoding.UTF8))
                // {
                //     binaryWriter.Write7BitEncodedInt32(data.Count);
                //     foreach (KeyValuePair<string, object> keyValuePair in data)
                //     {
                //         Type type = keyValuePair.Value.GetType();
                //         Serializer serializer = SerializerUtil.GetOrCreateSerializer(type);
                //         object value = keyValuePair.Value;
                //         binaryWriter.Write(LSReflection.GetTypeString(type));
                //         binaryWriter.Write(keyValuePair.Key);
                //         serializer.WriteBinaryObject(binaryWriter, value);
                //     }
                // }
                return true;
            }
            catch (Exception e)
            {
                Log.Error("Serialize failure with exception '{0}'.", e);
                return false;
            }
        }
        
        protected virtual Dictionary<string, object> DeserializeDefaultSavingCallBase(Stream stream)
        {
            Dictionary<string, object> data = new Dictionary<string, object>();
            
            // using (BinaryReader binaryReader = new BinaryReader(stream, Encoding.UTF8))
            // {
            //     int count = binaryReader.Read7BitEncodedInt32();
            //     for (int i = 0; i < count; i++)
            //     {
            //         string typeString = binaryReader.ReadString();
            //         Type type = LSReflection.GetType(typeString);
            //         Serializer serializer = SerializerManager.GetOrCreateSerializer(type);
            //         string key = binaryReader.ReadString();
            //         object value = serializer.ReadBinaryObject(binaryReader);
            //         data.Add(key, value);
            //     }
            // }
            
            return data;
        }
    }
}
